/**
    File        : ErrorLog.h
    Description : Message and error display and logging
    Author      : Raymond Marsh
    Created     : 08/01/2009
    Copyright 2009, 2010, 2011, 2012 Raymond Marsh

    This program is distributed under the terms of the GNU General Public License.
    To view a copy of the license see the file 'copying.txt'

    This file is part of the MyMoney Suite.

    MyMoney is free software: you can redistribute it and/or modify it under
    the terms of the GNU General Public License as published by the Free Software Foundation, either
    version 3 of the License, or (at your option) any later version.

    MyMoney is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along with MyMoney.
    If not, see <http://www.gnu.org/licenses/>.
**/

#include "..\include\ErrorLog.h"

namespace mm
{

const long COptMsgDlg::ID_CHECKBOX1 = wxNewId();

wxString wxVersion()
{
    wxString str = wxString::Format("%s.%s.%s - ", wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
#if wxUSE_UNICODE
        str <<"Unicode build";
#else
        str <<"ANSI build";
#endif
    return str;
}

void LogError(const wxString Message, const char* File, const char* Function, const int Line, const bool IsFatal)
{
    std::ofstream ErrorFile;
    ErrorFile.open( (const char*)mmErrLogFileName.c_str(), std::ios::out | std::ios::app);
    if (ErrorFile.is_open() )
    {
        ErrorFile << mmProgName;
        ErrorFile << " Version: " << AutoVersion::FULLVERSION_STRING <<"\n";
        ErrorFile << "wxVersion: " <<wxVersion() <<"\n";
        ErrorFile << "Error occured at ";
        ErrorFile << (mm::GetTimeStamp() ).c_str() << "\n";
        ErrorFile << "File: '" << File << "', Line: " << Line << "\n";
        ErrorFile << "In function: '" << Function << "'\n";
        (IsFatal) ? ErrorFile << "\n*** FATAL ERROR ***\n" : ErrorFile << "\n";
        ErrorFile << Message.c_str() << "\n\n******************************\n\n";
        ErrorFile.close();
    }
}

wxString GetTimeStamp()
{
    return (wxDateTime::Now() ).Format("%x %X");
}


///************************************************************************

CMsgDlgBase::CMsgDlgBase()
{

}

CMsgDlgBase::~CMsgDlgBase()
{

}

void CMsgDlgBase::SetUpDialog(wxWindow* pParent)
{
    m_pSizer = new wxBoxSizer(wxVERTICAL);
    m_pSizer->Add(new wxStaticText(pParent, wxID_ANY, m_Msg),
                  1, wxEXPAND | wxALL, 10);
    m_pSizer->Add(new wxStaticLine(pParent, wxID_ANY),
                  0, wxEXPAND);
}

void CMsgDlgBase::AddButtons(wxWindow* pParent, const unsigned char BtnFlags)
{
    m_pButtons = new wxStdDialogButtonSizer();
    if (BtnFlags != BTN_NULL)
    {
        if (BtnFlags & BTN_OK)
            m_pButtons->Add(new wxButton(pParent, wxID_OK, _("OK") ) );
        if (BtnFlags & BTN_YES)
            m_pButtons->Add(new wxButton(pParent, wxID_YES, _("Yes") ) );
        if (BtnFlags & BTN_SAVE)
            m_pButtons->Add(new wxButton(pParent, wxID_SAVE, _("Save") ) );
        if (BtnFlags & BTN_APPLY)
            m_pButtons->Add(new wxButton(pParent, wxID_APPLY, _("Apply") ) );
        if (BtnFlags & BTN_CLOSE)
            m_pButtons->Add(new wxButton(pParent, wxID_CLOSE, _("Close") ) );
        if (BtnFlags & BTN_NO)
            m_pButtons->Add(new wxButton(pParent, wxID_NO, _("No") ) );
        if (BtnFlags & BTN_CANCEL)
            m_pButtons->Add(new wxButton(pParent, wxID_CANCEL, _("Cancel") ) );
        if (BtnFlags & BTN_HELP)
            m_pButtons->Add(new wxButton(pParent, wxID_HELP, _("Help") ) );
    }
    else
    {
        m_pButtons->Add(new wxButton(pParent, wxID_OK, _("OK") ) );
    }
    m_pButtons->Realize();
    m_pSizer->Add(m_pButtons, 0, wxALIGN_RIGHT | wxALL, 10);
}

void CMsgDlgBase::ConnectHandlers(wxWindow* pParent, const unsigned char BtnFlags)
{
    if (BtnFlags & BTN_OK)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnOK, this, wxID_OK);
    if (BtnFlags & BTN_YES)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnYes, this, wxID_YES);
    if (BtnFlags & BTN_SAVE)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnSave, this, wxID_SAVE);
    if (BtnFlags & BTN_APPLY)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnApply, this, wxID_APPLY);
    if (BtnFlags & BTN_CLOSE)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnClose, this, wxID_CLOSE);
    if (BtnFlags & BTN_NO)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnNo, this, wxID_NO);
    if (BtnFlags & BTN_CANCEL)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnCancel, this, wxID_CANCEL);
    if (BtnFlags & BTN_HELP)
        pParent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlgBase::OnHelp, this, wxID_HELP);
}

void CMsgDlgBase::LogError(bool IsFatal)
{
    std::ofstream ErrorFile;
    ErrorFile.open( (const char*)mmErrLogFileName.c_str(), std::ios::out | std::ios::app);
    if (ErrorFile.is_open() )
    {
        ErrorFile << mmProgName;
        ErrorFile << " Version: " << AutoVersion::FULLVERSION_STRING <<"\n";
        ErrorFile << "wxVersion: " <<wxVersion() <<"\n";
        ErrorFile << "Error occured at ";
        ErrorFile << (mm::GetTimeStamp() ).c_str() << "\n";
        ErrorFile << "File: '" << m_File.c_str() << "', Line: " << m_Line << "\n";
        ErrorFile << "In function: '" << m_Function.c_str() << "'\n";
        (IsFatal) ? ErrorFile << "\n*** FATAL ERROR ***\n" : ErrorFile << "\n";
        ErrorFile << m_Msg.c_str() << "\n\n******************************\n\n";
        ErrorFile.close();
    }
}


///************************************************************************

CMsgDlg::CMsgDlg(wxWindow* pParent, const wxString Message, const unsigned char BtnFlags)
: wxDialog(pParent, wxID_ANY, _("Message") )
{
    m_pSizer   = NULL;
    m_pButtons = NULL;
    m_pParent  = pParent;
    m_Msg      = Message;

    SetUpDialog(this);
    AddButtons(this, BtnFlags);
    SetSizerAndFit(m_pSizer);
    Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CMsgDlg::OnButtonClick, this);
}

CMsgDlg::~CMsgDlg()
{

}

void CMsgDlg::OnButtonClick(wxCommandEvent& event)
{
    EndModal(event.GetId() );
}


///************************************************************************


COptMsgDlg::COptMsgDlg(wxWindow* pParent, const wxString Message, bool* pIsChecked, const unsigned char BtnFlags)
: wxDialog(pParent, wxID_ANY, _("Message") )
{
    m_pSizer   = NULL;
    m_pButtons = NULL;
    m_pParent  = pParent;
    m_Msg      = Message;

    SetUpDialog(this);

    m_pCheckbox = new wxCheckBox(this,
                                 ID_CHECKBOX1,
                                 _("Do not show this message again"),
                                 wxDefaultPosition,
                                 wxDefaultSize,
                                 0,
                                 wxGenericValidator(pIsChecked) );
    m_pSizer->Insert(1, m_pCheckbox, 0, wxALIGN_LEFT | wxALL, 10);

    AddButtons(this, BtnFlags);
    SetSizerAndFit(m_pSizer);
    Bind(wxEVT_COMMAND_BUTTON_CLICKED, &COptMsgDlg::OnButtonClick, this);
}

COptMsgDlg::~COptMsgDlg()
{

}

void COptMsgDlg::OnButtonClick(wxCommandEvent& event)
{
    if (Validate() && TransferDataFromWindow() )
    {
        const int id = event.GetId();
        if (IsModal() )
            EndModal(id);
        else
        {
            SetReturnCode(id);
            this->Show(false);
        }
    }
}


///************************************************************************


CErrorDlg::CErrorDlg(wxWindow* pParent, const wxString Message, const char* File, const char* Function, const int Line)
: wxDialog(pParent, wxID_ANY, _("Error") )
{
    m_pSizer   = NULL;
    m_pButtons = NULL;
    m_pParent = pParent;
    m_Msg = Message;
    m_File = File;
    m_Function = Function;
    m_Line = Line;

#ifdef _DEBUG
    m_Msg += wxString::Format("\n\nFile     : %s\nFunction : %s\nLine #   : %s", m_File, m_Function, m_Line);
#else
    LogError(false);
    m_Msg = wxString::Format(_("An error has occured!\n"
                               "A copy of the error report has been\n"
                               "saved at '%s'\n"
                               "Please report the error to the\n"
                               "developers at www.%s.sourceforge.com"),
                               mmErrLogFileName,
                               mmProgName);
#endif
    SetUpDialog(this);
    AddButtons(this, BTN_OK);
    SetSizerAndFit(m_pSizer);
    ConnectHandlers(this, BTN_OK);
}

CErrorDlg::~CErrorDlg()
{

}


///************************************************************************


CFatalErrorDlg::CFatalErrorDlg(wxWindow* pParent, const wxString Message, const char* File, const char* Function, const int Line)
: wxDialog(pParent, wxID_ANY, _("Error") )
{
    m_pParent = pParent;
    m_Msg = Message;
    m_File = File;
    m_Function = Function;
    m_Line = Line;

#ifndef _DEBUG
    LogError(true);
    m_Msg =  wxString::Format(_("%s has encountered an error that it can not"), mmProgName);
    m_Msg += wxString::Format(_("recover from. %s will have to be shut down."), mmProgName);
    m_Msg += _("Information about this error has been saved");
    m_Msg += wxString::Format(_("to the file '%s'.\nWe appoligize for the inconvenience."), mmErrLogFileName);
#endif

    SetUpDialog(this);
    AddButtons(this, BTN_OK);
    SetSizerAndFit(m_pSizer);
    Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CFatalErrorDlg::OnOK, this, wxID_OK);
}

CFatalErrorDlg::~CFatalErrorDlg()
{

}

void CFatalErrorDlg::OnOK(wxCommandEvent& event)
{
    wxWindow* win = wxWindow::FindWindowByName("MoneyFrame");
    if (win)
        win->Close(true);

    if (IsModal() )
        EndModal(wxID_OK);
    else
    {
        SetReturnCode(wxID_OK);
        this->Show(false);
    }
}



///************************************************************************

}; // namespace mmDlg

